// Copyright 2013 Google Inc. All Rights Reserved.

#include <errno.h>

#include <irt_syscalls.h>
#include <nacl_fcntl.h>

#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>


int __open(const char *filename, int flags, int mode) {
  int newfd;
  int nacl_flags = 0;
  int result;

  ENOSYS_IF_NULL(__nacl_irt_open);

  switch ((flags & O_ACCMODE)) {
    case O_RDONLY:
      nacl_flags |= NACL_ABI_O_RDONLY;
      break;
    case O_WRONLY:
      nacl_flags |= NACL_ABI_O_WRONLY;
      break;
    case O_RDWR:
      nacl_flags |= NACL_ABI_O_RDWR;
      break;
    default:
      // |flags| has broken access mode so we want to set a broken value
      // for |nacl_flags| as well. With NaCl's ABI, NACL_ABI_O_ACCMODE (3)
      // is the broken value so we will set this value.
      nacl_flags |= NACL_ABI_O_ACCMODE;
  }
  if ((flags & O_CREAT))
    nacl_flags |= NACL_ABI_O_CREAT;
  if ((flags & O_TRUNC))
    nacl_flags |= NACL_ABI_O_TRUNC;
  if ((flags & O_APPEND))
    nacl_flags |= NACL_ABI_O_APPEND;
  if ((flags & O_EXCL))
    nacl_flags |= NACL_ABI_O_EXCL;
  if ((flags & O_NONBLOCK))
    nacl_flags |= NACL_ABI_O_NONBLOCK;
  if ((flags & O_NDELAY))
    nacl_flags |= NACL_ABI_O_NDELAY;
  if ((flags & O_SYNC))
    nacl_flags |= NACL_ABI_O_SYNC;
  // Bionic does not have O_ASYNC.

  result = __nacl_irt_open(filename, nacl_flags, mode, &newfd);
  if (result != 0) {
    errno = __nacl_abi_errno_to_errno(result);
    return -1;
  }
  return newfd;
}


int _open(const char *pathname, int flags, ...)
{
    mode_t  mode = 0;
    flags |= O_LARGEFILE;
    if (flags & O_CREAT)
    {
        va_list  args;

        va_start(args, flags);
        mode = (mode_t) va_arg(args, int);
        va_end(args);
    }

    return __open(pathname, flags, mode);
}

weak_alias(_open, open)